package org.example.diary.config;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.annotation.Resource;
import org.example.diary.entity.dao.SysRole;
import org.example.diary.entity.dao.SysRoleMenu;
import org.example.diary.entity.dao.SysUser;
import org.example.diary.entity.dto.LoginUser;
import org.example.diary.enums.BizErrorCode;
import org.example.diary.enums.StatusEnums;
import org.example.diary.exceptions.BizAssertUtil;
import org.example.diary.mapper.RoleMapper;
import org.example.diary.mapper.SysRoleMenuMapper;
import org.example.diary.mapper.UserMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter;

import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Eric
 * @date 2023-01-27 16:32
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {

    @Resource
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
    @Resource
    private UserMapper userMapper;
    @Resource
    private RoleMapper roleMapper;
    @Resource
    private SysRoleMenuMapper sysRoleMenuMapper;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public UserDetailsService userDetailsService() {
        return username -> {
            // 实现你的用户查询逻辑
            SysUser sysUser = userMapper.selectOne(new LambdaQueryWrapper<SysUser>()
                    .eq(SysUser::getUsername, username)
                    .eq(SysUser::getStatus, StatusEnums.NORMAL.getStatus())
            );
            BizAssertUtil.isTrue(ObjectUtil.isNull(sysUser), BizErrorCode.USER_NOT_EXISTS);
            //角色查询
            SysRole sysRole = roleMapper.selectById(sysUser.getRole());

            LoginUser loginUser = new LoginUser(sysUser, Collections.singletonList(sysRole.getName()));
            return loginUser;
        };
    }


    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                // 禁用 CSRF 防护（通常用于 API 或无状态应用，Web 应用建议保持开启）
                .csrf(csrf -> csrf.disable())
                // 配置请求授权规则
                .authorizeHttpRequests(auth -> auth
                        // 允许所有人访问的路径（无需登录）
                        .requestMatchers("user_login").permitAll()
                        .requestMatchers("user_logout").permitAll()
                        // 需要 ADMIN 角色的路径
                        .requestMatchers("/admin/**").hasRole("ADMIN")
                        // 其他所有请求需要认证（登录）
                        .anyRequest().authenticated()
                )
                // 注销配置
                /*.logout(logout -> logout
                        // 自定义注销URL（默认是 /logout）
                        .logoutUrl("/logout")
                        // 注销成功后跳转的页面（带logout参数用于前端显示消息）
                        .logoutSuccessUrl("/login?logout")
                        // 允许所有人访问注销功能
                        .permitAll()
                )*/;
        http.addFilterBefore(jwtAuthenticationTokenFilter, LogoutFilter.class);
        http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }

    @Bean
    public AuthenticationManager authenticationManager(UserDetailsService userDetailsService, PasswordEncoder passwordEncoder) {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setUserDetailsService(userDetailsService);
        provider.setPasswordEncoder(passwordEncoder);
        return new ProviderManager(provider);
    }


}
